package com.mjk.common.core.jdbc.service.plus.wrap;


import com.mjk.common.base.constns.BeeCommonConstns;
import com.mjk.common.base.model.BaseEntity;
import com.mjk.common.base.request.BaseDto;
import com.mjk.common.core.jdbc.annotation.Filed;
import com.mjk.common.core.jdbc.service.plus.idbservice.BeeDBService;
import com.mjk.common.core.jdbc.util.provider.SelectSqlProvider;
import com.mjk.common.core.jdbc.util.provider.UpdateSqlProvider;
import com.mjk.common.tools.lambada.LambdaMeta;
import com.mjk.common.tools.lambada.LambdaReflectionUtil;
import com.mjk.common.tools.lambada.LambdaUtils;
import com.mjk.common.tools.lambada.function.BeeFunction;
import com.mjk.common.tools.springextend.BeeSpringBean;
import com.mjk.common.util.*;
import lombok.Getter;
import org.apache.ibatis.reflection.property.PropertyNamer;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 条件查询类
 */
public class BeeQueryWrapper {

    protected final BeeDBService beeDBService = BeeSpringBean.getBean(BeeDBService.class);
    /**
     * 占位符
    * */
    protected final BeeQueryWrapper typedThis = this;
    /**
     * 查询属性
     */
    protected final StringBuilder select = new StringBuilder();
    /**
     * 条件
     */
    protected final List<String> condiations = new ArrayList<>();

    /**
     * 保存的条件值 用户参数赋值
     */
    private final Map<String,Object> params = new HashMap<>();
    /**
     * 是否只取单条数据
     */
    private boolean onlyOne = false;
    /**
     * groupby 语句
     */
    private String groupBy;
    /**
     * orderby 语句
     */
    private String orderBy;
    /**
     * 每页大小
     */
    @Getter
    private int pageSize;
    /**
     * 起始页
     */
    @Getter
    private int pageStart;

    /**
     * 左连接 表
     */
    //protected final Map<Class<?>,String> joinTable = new HashMap<>();
    /**
     * 自增字段
     */
    private List<String> incList = new ArrayList<>();

    /**
     * 单表实例
     */
    private BaseEntity entity;

    private String notIn = "not in";

    private String paramsStr = " #{wrap.params.%s}";
    /**
     * 条件枚举
     */
    @Getter
    public enum Condition{
        AND(" and "),OR(" or ");
        private final String conditionVal;
        Condition(String name){
            this.conditionVal = name;
        }
    }

    public BeeQueryWrapper(Class<? extends BaseEntity> instance) {
        this.entity = ReflectionUtils.newInstance(instance);
        this.select();//默认全字段
    }

    public BeeQueryWrapper(Class<? extends BaseEntity> instance, BaseDto dto) {
        this.entity = ReflectionUtils.newInstance(instance);
        this.select();//默认全字段
        if (ObjectUtils.isNotEmpty(dto.getPageStart()))
            this.pageStart = dto.getPageStart();
        if (ObjectUtils.isNotEmpty(dto.getPageSize()))
            this.pageSize = dto.getPageSize();
    }
    public BeeQueryWrapper(BaseEntity instance) {
        this.entity = instance;
        this.select();//默认全字段
    }

    public BeeQueryWrapper(BaseEntity instance, BaseDto dto) {
        this.entity = instance;
        this.select();//默认全字段
        if (ObjectUtils.isNotEmpty(dto.getPageStart()))
            this.pageStart = dto.getPageStart();
        if (ObjectUtils.isNotEmpty(dto.getPageSize()))
            this.pageSize = dto.getPageSize();
    }

    public static BeeQueryWrapper getWrapper(BaseEntity entiy) {
        return new BeeQueryWrapper(entiy);
    }

    public static BeeQueryWrapper getWrapper(Class<? extends BaseEntity> instance) {
        return new BeeQueryWrapper(instance);
    }
    public BaseEntity getInstance() {
        return this.entity;
    }

    public Class<? extends BaseEntity> getInstanceClass() {
        return this.entity.getClass();
    }

    public void setInstance(BaseEntity instance) {
        this.entity = instance;
    }
    /**
     * 设置只取一条数据
     */
    public final void onlyOne(){
        this.onlyOne = true;
    }

    public List<String> getIncList() {
        return this.incList;
    }

    /**
     * 设置自增字段
     *
     * @param columns
     * @return
     */
    public final <T extends BaseEntity> BeeQueryWrapper inc(BeeFunction<T, ?>... columns) {
        for (BeeFunction<T, ?> item : columns) {
            incList.add(getFiledName(item));
        }
        return typedThis;
    }


    public final BeeQueryWrapper setPage(int pageStart,int pageSize){
        this.pageStart = pageStart;
        this.pageSize = pageSize;
        return typedThis;
    }

    /**
     * 设置groupby 语句
     */
    public final BeeQueryWrapper groupBy(String groupSql){
        this.groupBy = groupSql;
        return typedThis;
    }

    /**
     * 设置orderby 语句
     */
    public final BeeQueryWrapper orderBy(String orderBySql){
        this.orderBy = orderBySql;
        return typedThis;
    }

    public final <T extends BaseEntity> BeeQueryWrapper orderByAsc(BeeFunction<T, ?> column) {
        this.orderBy = getFiledName(column) + " asc ";
        return typedThis;
    }

    public final <T extends BaseEntity> BeeQueryWrapper orderByDesc(BeeFunction<T, ?> column) {
        this.orderBy = getFiledName(column) + " desc ";
        return typedThis;
    }

    /**
     * 设置值
     */
    public final <T extends BaseEntity> BeeQueryWrapper set(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            LambdaReflectionUtil.invoke(this.getInstance(), getFiledName(column), val);
        return typedThis;
    }

    public final <T extends BaseEntity> BeeQueryWrapper set(BeeFunction<T, ?> column, Object val) {
        LambdaReflectionUtil.invoke(this.getInstance(), getFiledName(column), val);
        return typedThis;
    }

    /**
     * 获取查询字段 如果为空，这查询所有字段
     */
    @SafeVarargs
    public final <T extends BaseEntity> BeeQueryWrapper select(BeeFunction<T, ?>... columns) {
        List<String> results = new ArrayList<>();
        for(BeeFunction<T, ?> item : columns) {
            results.add(getFiledName(item));
        }
        select.setLength(0);
        select.append(StrUtils.join(results, ","));
        return typedThis;
    }
    /**
     * 获取默认 select 字段 ，为entity中的所有字段
     */
    public final BeeQueryWrapper select() {
        select.setLength(0);
        select.append(SelectSqlProvider.getSelectFiled(entity));
        return typedThis;
    }

    /**
     * 获取默认 select 字段 使用字符串
     */
    public final BeeQueryWrapper select(String fields) {
        select.setLength(0);
        select.append(fields);
        return typedThis;
    }
    /**
     * 不选中的字段
     *
     * @param columns
     * @param <T>
     * @return
     */
    public final <T extends BaseEntity> BeeQueryWrapper notSelect(BeeFunction<T, ?>... columns) {
        List<String> results = new ArrayList<>();
        for (BeeFunction<T, ?> item : columns) {
            results.add(getFiledName(item));
        }
        select.setLength(0);
        List<String> allFileds = SelectSqlProvider.getSelectFileds(entity);
        List<String> fileds = allFileds.stream().filter(item -> !results.contains(item)).toList();
        select.append(StrUtils.join(fileds, ","));
        return typedThis;
    }
    /**
     * 获取update字段
     */
    public final BeeQueryWrapper update(){
        UpdateSqlProvider.getUpdateFiled(entity);
        return typedThis;
    }


    /**
     * 添加文本条件
     */
    public final BeeQueryWrapper condition(String condition, Object...val){
        this.condition(Condition.AND,condition,val);

        return typedThis;
    }

    public final void condition(Condition conditionVal, String condition, Object... val){
        Pattern r = Pattern.compile(BeeCommonConstns.TEMPLATE_PARAMS_MATH);
        Matcher m = r.matcher(condition);
        int index =0;
        while (m.find()) {
            String match = m.group(1);
            if(index <= val.length-1) {
                params.put(match, val[index]);
            }
            String tmp = "wrap.params." + match;
            if(!condition.contains(tmp)) {
                condition = condition.replace(match,tmp);
            }
            index++;
        }
        if(this.condiations.size()>0){
            this.condiations.add(conditionVal.conditionVal +"("+condition+")");
        }else{
            this.condiations.add("("+condition+")");
        }

    }


    /**
     * 相等
     */
    public <T extends BaseEntity> BeeQueryWrapper eq(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            eq(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper eq(BeeFunction<T, ?> column,Object val){
        eq(Condition.AND, column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void eq(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column),"=",val);
    }

    public <T extends BaseEntity> BeeQueryWrapper eq(boolean need, String column, Object val) {
        if (need)
            eq(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper eq(String column, Object val) {
        eq(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> void eq(Condition conditionVal, String column, Object val) {
        addCondition(conditionVal, column, "=", val);
    }

    /**
     * 不相等
     */
    public <T extends BaseEntity> BeeQueryWrapper ne(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            ne(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper ne(BeeFunction<T, ?> column,Object val){
        ne(Condition.AND,column,val);
        return typedThis;
    }
    public <T extends BaseEntity> void ne(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column),"!=",val);
    }
    /**
     * 大于
     */
    public <T extends BaseEntity> BeeQueryWrapper gt(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            gt(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper gt(BeeFunction<T, ?> column,Object val){
        gt(Condition.AND,column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void gt(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column),">",val);
    }
    /**
     * 大于等于
     */
    public <T extends BaseEntity> BeeQueryWrapper ge(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            ge(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper ge(BeeFunction<T, ?> column,Object val){
        ge(Condition.AND,column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void ge(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column),">=",val);
    }
    /**
     * 小于
     */
    public <T extends BaseEntity> BeeQueryWrapper it(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            it(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper it(BeeFunction<T, ?> column, Object val) {
        it(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> void it(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column),"<",val);
    }
    /**
     * 小于等于
     */
    public <T extends BaseEntity> BeeQueryWrapper ie(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            ie(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper ie(BeeFunction<T, ?> column, Object val) {
        ie(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> void ie(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column),"<=",val);
    }
    /**
     * BETWEEN 值1 AND 值2
     */
    public <T extends BaseEntity> BeeQueryWrapper between(boolean need, BeeFunction<T, ?> column, Object val, Object val1) {
        if (need)
            between(Condition.AND, column, val, val1);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper between(BeeFunction<T, ?> column,Object val,Object val1){
        between(Condition.AND,column, val,val1);
        return typedThis;
    }
    public <T extends BaseEntity> void between(Condition conditionVal, BeeFunction<T, ?> column, Object val, Object val1){
        addCondition(conditionVal,getFiledName(column),"between",val,val1);
    }
    /**
     * notBetween 值1 AND 值2
     */
    public <T extends BaseEntity> BeeQueryWrapper notBetween(boolean need, BeeFunction<T, ?> column, Object val, Object val1) {
        if (need)
            notBetween(Condition.AND, column, val, val1);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper notBetween(BeeFunction<T, ?> column,Object val,Object val1){
        notBetween(Condition.AND,column, val,val1);
        return typedThis;
    }
    public <T extends BaseEntity> void notBetween(Condition conditionVal, BeeFunction<T, ?> column, Object val, Object val1){
        addCondition(conditionVal,getFiledName(column),"notBetween",val,val1);
    }
    /**
     * LIKE '%值%'
     */
    public <T extends BaseEntity> BeeQueryWrapper like(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            like(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper like(BeeFunction<T, ?> column,Object val){
        like(Condition.AND,column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void like(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column),"like","%"+val+"%");
    }
    /**
     * notLike '%值%'
     */
    public <T extends BaseEntity> BeeQueryWrapper notLike(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            notLike(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper notLike(BeeFunction<T, ?> column,Object val){
        notLike(Condition.AND,column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void notLike(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column)," not Like ","%"+val+"%");
    }
    /**
     *  LIKE '%值'
     */
    public <T extends BaseEntity> BeeQueryWrapper likeLeft(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            likeLeft(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper likeLeft(BeeFunction<T, ?> column,Object val){
        likeLeft(Condition.AND,column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void likeLeft(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column)," like ","%"+val);
    }
    /**
     *  LIKE '值%'
     */
    public <T extends BaseEntity> BeeQueryWrapper likeRight(boolean need, BeeFunction<T, ?> column, Object val) {
        if (need)
            likeRight(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper likeRight(BeeFunction<T, ?> column,Object val){
        likeRight(Condition.AND,column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void likeRight(Condition conditionVal, BeeFunction<T, ?> column, Object val){
        addCondition(conditionVal,getFiledName(column)," like ",val+"%");
    }

    /**
     * in
     */
    public <T extends BaseEntity> BeeQueryWrapper in(boolean need, BeeFunction<T, ?> column, List<?> val) {
        if (need)
            in(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper in(BeeFunction<T, ?> column,List<?> val){
        in(Condition.AND,column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void in(Condition conditionVal, BeeFunction<T, ?> column, List<?> val){
        addCondition(conditionVal,getFiledName(column),"in",val);
    }
    /**
     * notin
     */
    public <T extends BaseEntity> BeeQueryWrapper notIn(boolean need, BeeFunction<T, ?> column, List<?> val) {
        if (need)
            notIn(Condition.AND, column, val);
        return typedThis;
    }

    public <T extends BaseEntity> BeeQueryWrapper notIn(BeeFunction<T, ?> column,List<?> val){
        notIn(Condition.AND,column, val);
        return typedThis;
    }
    public <T extends BaseEntity> void notIn(Condition conditionVal, BeeFunction<T, ?> column, List<?> val) {
        addCondition(conditionVal, getFiledName(column), notIn,val);
    }
    public void addCondition(Condition conditionVal,String column,String condition,Object val) {
        params.put(getParamsStr(column),val);
        if(CollectionUtils.isEmpty(condiations)) {//如果条件为空 表示第一个条件 不需要添加and / or
            if ("in".equals(condition) || notIn.equals(condition)){
                condiations.add(getInStr(column,condition,val));
            } else {
                condiations.add(column + " " + condition + String.format(paramsStr, getParamsStr(column)));
            }
        } else {
            if ("in".equals(condition) || notIn.equals(condition)){
                condiations.add(getInStr(column,condition,val));
            } else {
                condiations.add(conditionVal.getConditionVal() + column + " " + condition + String.format(paramsStr, getParamsStr(column)));
            }
        }
    }

    public void addCondition(Condition conditionVal,String column,String condition,Object val,Object val1) {
        if("between".equals(condition) || "notBetween".equals(condition)) {
            params.put(getParamsStr(column)+"start",val);
            params.put(getParamsStr(column)+"end",val1);
            if(CollectionUtils.isEmpty(condiations)) {//如果条件为空 表示第一个条件 不需要添加and / or
                condiations.add(column + " " + condition + " #{wrap.params." + getParamsStr(column) + "start}" + Condition.AND.conditionVal + String.format(paramsStr, getParamsStr(column) + "end"));
            } else {
                condiations.add(conditionVal.getConditionVal() + " " + column + " " + condition + String.format(paramsStr, getParamsStr(column) + "start") + Condition.AND.conditionVal + String.format(paramsStr, getParamsStr(column) + "end"));
            }
        }else {
            addCondition(conditionVal, column, condition, val1);
        }
    }

    public String getParamsStr(String str){
        if(str.contains(".")){
            return str.replace(".","");
        }
        return str;
    }

    /**
     * 组装in sql语句
     */
    public String getInStr(String column,String condition,Object val){
        StringBuilder in = new StringBuilder(column+" "+condition+" (" );
        if(val instanceof List list){
            int index = 0;
            List<String> instr= new ArrayList<>();
            for(Object item : list){
                params.put(column+index,item);
                instr.add("#{wrap.params."+column+index+"}");
                index ++;
            }
            in.append(StrUtils.join(instr,","));
        }
        in.append(")");
        return in.toString();
    }

    /**
     * 通过lamdba 表达式获取属性名称
     */
    protected <T extends BaseEntity> String getFiledName(BeeFunction<T, ?> column) {
        LambdaMeta meta = LambdaUtils.extract(column);
        BaseEntity baseEntity = (BaseEntity) ReflectionUtils.newInstance(meta.getInstantiatedClass());
        String fieldName = PropertyNamer.methodToProperty(meta.getImplMethodName());
        //返回数据库字段
        Field f = ReflectionUtils.getField(baseEntity.getClass(), fieldName, true);
        //获取属性字段名称
        Filed filed = f.getAnnotation(Filed.class);
        String fileName = f.getName();
        if (null != filed) {
            fileName = ObjectUtils.isEmpty(filed.cloum()) ? f.getName() : filed.cloum();
        }
//        if(joinTable.containsKey(Objects.requireNonNull(baseEntity).getClass())) {
//            return joinTable.get(baseEntity.getClass()) + "." + fileName;
//        } else {
            return fileName;
//        }
    }

    /**
     * 查询一条数据
     *
     * @param <T>
     * @return
     */
    public <T extends BaseEntity> T one() {
        return (T) beeDBService.findOneByWrapper(this);
    }

    /**
     * 查询多条数据
     *
     * @param <T>
     * @return
     */
    public <T extends BaseEntity> List<T> list() {
        return beeDBService.findManyByWrapper(this);
    }

    public String groupBy(){
        return this.groupBy;
    }

    public String orderBy(){
        return this.orderBy;
    }

    public boolean isOnlyOne() {
        return this.onlyOne;
    }

    public String toSelect() {
        return select.toString();
    }

    public String toWherSql() {
        return  StrUtils.join(condiations," ");
    }
}
